package com.elitel.frame.business.service.common.impl;

import com.alibaba.fastjson.JSONObject;
import com.elitel.common.utils.SpringUtils;
import com.elitel.frame.base.service.SysPrjServiceService;
import com.elitel.frame.business.service.common.CommonServer;
import com.elitel.frame.business.service.common.CommonServerProcessor;
import com.elitel.frame.core.util.ApplicationContextHelper;
import com.elitel.frame.main.entity.SysPrjservice;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static com.elitel.common.core.constant.RequestConstant.SERVICE_ID;

/**
 * 通用接口实现类 此类中禁止更改任何代码;
 * 若需要添加统一前置逻辑请实现CommonServicePre接口后, 并在CommonServiceConfig中通过本类的addPre方法添加;
 * 若需要添加统一后置逻辑请实现CommonServicePost接口后, 并在CommonServiceConfig中通过本类的addPost方法添加;
 *
 * @author mulis
 */

public class CommonServerExecutor {
    private static final Logger logger = LoggerFactory.getLogger(CommonServerExecutor.class);
    /**
     * 前置处理器
     */
    private final List<CommonServerProcessor> preList = new ArrayList<>();

    /**
     * 业务逻辑Map
     * key:servicetype(服务类型)
     * value:bean(具体实现类)
     */
    private final Map<String, Config> beanMap = new HashMap<>();

    /**
     * 后置处理器
     */
    private final List<CommonServerProcessor> postList = new ArrayList<>();


    /**
     * 添加前置处理逻辑
     *
     * @param pre
     */
    public void addPre(CommonServerProcessor pre) {
        this.preList.add(pre);
    }


    public void registerService(String serviceType, Config commonService) {
        this.beanMap.put(serviceType, commonService);
    }


    /**
     * 添加后置处理逻辑
     *
     * @param post
     */
    public void addPost(CommonServerProcessor post) {
        this.postList.add(post);
    }

    public Object request(Map params, HttpServletRequest request, HttpServletResponse response) {

        // 1.前置处理
        for (CommonServerProcessor commonServicePre : preList) {
            commonServicePre.pre(params, request, response);
        }
        // 2.业务处理
        Object res = this.doRequest(params, request, response);
        // 3.后置处理
        for (CommonServerProcessor commonServicePost : postList) {
            res = commonServicePost.post(params, res, request, response);
        }
        return res;

    }

    /**
     * 发起请求
     *
     * @param paramMap 参数
     * @return
     */
    private Object doRequest(Map<String, Object> paramMap, HttpServletRequest request, HttpServletResponse response) {
        Object res = null;
        String serviceCode = (String) paramMap.get(SERVICE_ID);
        // 1.根据serviceId获取serviceType
        SysPrjServiceService sysPrjServiceService = ApplicationContextHelper.getApplicationContext().getBean(SysPrjServiceService.class);
        SysPrjservice sysPrjservice = sysPrjServiceService.getSysPrjserviceByServiceCode(serviceCode);
        String serviceType = sysPrjservice.getServicetype();

        // 2.根据serviceType获取bean类
        Config serviceConfigInfo = beanMap.get(serviceType);

        // 3.通过类在Spring容器中获取bean和参数类型
        Object bean = null;
        Class<?> paramClass = null;
        if (serviceConfigInfo != null) {
            if (serviceConfigInfo.getServiceClass() != null) {
                bean = SpringUtils.getBean(serviceConfigInfo.getServiceClass());
            } else if (serviceConfigInfo.getServiceClassName() != null) {
                try {
                    Class<?> aClass = Class.forName(serviceConfigInfo.getServiceClassName());
                    bean = SpringUtils.getBean(aClass);
                } catch (ClassNotFoundException e) {
                    logger.error("服务类不存在", e);
                    throw new RuntimeException("服务类不存在");
                }
            }
            if (serviceConfigInfo.getServiceParamClass() != null) {
                paramClass = serviceConfigInfo.getServiceParamClass();
            } else if (serviceConfigInfo.getServiceParamClassName() != null) {
                try {
                    paramClass = Class.forName(serviceConfigInfo.getServiceParamClassName());
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException("参数类不存在");
                }
            }
        }
        if (bean == null) {
            throw new RuntimeException("服务对应的处理类不存在");
        }

        // 4.判断是不是CommonService的子类
        if (bean instanceof CommonServer) {
            CommonServer commonService = (CommonServer) bean;
            Object paramDTO;
            // 5.参数转换一下 自定义接口使用参数的时候强转一下就可以使用了
            if (paramClass != null) {
                paramDTO = JSONObject.parseObject(JSONObject.toJSONString(paramMap), paramClass);
            } else {
                paramDTO = paramMap;
            }
            // 6.调用bean的doRequest
            res = commonService.doRequest(paramDTO, request, response);
        }

        return res;
    }


    /**
     * 服务配置信息
     */
    @Setter
    @Getter
    public static class Config {
        /**
         * 服务类
         */
        private Class<?> serviceClass;
        /**
         * 服务类名
         */
        private String serviceClassName;
        /**
         * 服务参数类
         */
        private Class<?> serviceParamClass;
        /**
         * 服务参数类名
         */
        private String serviceParamClassName;

        public static Config set(Class<?> serviceClass, Class<?> serviceParamClass) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClass(serviceClass);
            serviceConfigInfo.setServiceParamClass(serviceParamClass);
            return serviceConfigInfo;
        }

        public static Config set(String serviceClassName, Class<?> serviceParamClass) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClassName(serviceClassName);
            serviceConfigInfo.setServiceParamClass(serviceParamClass);
            return serviceConfigInfo;
        }

        public static Config set(Class<?> serviceClass, String serviceParamClassName) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClass(serviceClass);
            serviceConfigInfo.setServiceParamClassName(serviceParamClassName);
            return serviceConfigInfo;
        }

        public static Config set(String serviceClassName, String serviceParamClassName) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClassName(serviceClassName);
            serviceConfigInfo.setServiceClassName(serviceParamClassName);
            return serviceConfigInfo;
        }

        public static Config set(String serviceClassName) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClassName(serviceClassName);
            return serviceConfigInfo;
        }

        public static Config set(Class<? extends CommonServer> serviceClass) {
            Config serviceConfigInfo = new Config();
            serviceConfigInfo.setServiceClass(serviceClass);
            return serviceConfigInfo;
        }
    }


}
